import {
  ButtonInteraction,
  CacheType,
  ChatInputCommandInteraction,
  Events,
} from 'discord.js';
import bot from '../../bot';
import { logger } from '../../util/logger';
import { commandRegistry } from '../commandRegistry';
import { Embed } from '../../classes/embed';
import { getUserEntry, getUserPermissionsFromEntry } from '../../util/db/auth';
import { buttonRegistry } from '../buttonRegistry';

const handleChatInputCommand = async (
  interaction: ChatInputCommandInteraction<CacheType>,
) => {
  const command = commandRegistry.get(interaction.commandName);
  if (!command) {
    await interaction.reply({
      embeds: [
        new Embed().error(
          new Error(
            `Couldn't find interaction by name: ${interaction.commandName}`,
          ),
        ),
      ],
    });
    return;
  }
  let lookup: ReturnType<typeof getUserEntry> | undefined = undefined;
  if (process.env.FORCE_CREATE_USER === interaction.user.id) {
    logger.info(interaction.user, 'Force-Creating User in DB...');
    lookup = getUserEntry(interaction.user, true);
    await (await lookup)?.save();
  }
  if (command.requiredBotPermissions.length > 0) {
    if (!lookup) lookup = getUserEntry(interaction.user);
    const dbUser = await lookup;
    if (!dbUser) {
      await interaction.reply({
        embeds: [
          new Embed()
            .error("You don't have permission to run this command.")
            .setFooter({
              text: 'ERR_NO_DB_ENTRY',
            }),
        ],
      });
      return;
    }
    const permissions = await getUserPermissionsFromEntry(dbUser);
    const missingPermissions = command.requiredBotPermissions.filter(
      v => !permissions[v],
    );
    if (missingPermissions.length !== 0) {
      await interaction.reply({
        embeds: [
          new Embed()
            .error(
              `You don't have permission to run this command.
Missing Permission${
                missingPermissions.length === 1
                  ? ` \`${missingPermissions[0]}\``
                  : `s:
${missingPermissions.map(v => `- \`${v}\``).join('\n')}`
              }`,
            )
            .setFooter({
              text: 'ERR_MISSING_PERMS',
            }),
        ],
        ephemeral: true,
      });
      return;
    }
  }
  command.invoke(interaction);
};

const handleButtonInteraction = async (interaction: ButtonInteraction) => {
  const item = buttonRegistry.get(interaction.customId);
  if (!item) {
    await interaction.reply({
      embeds: [
        new Embed().error(
          new Error(
            `Couldn't find interaction by name: ${interaction.customId}`,
          ),
        ),
      ],
    });
    return;
  }
  let lookup: ReturnType<typeof getUserEntry> | undefined = undefined;
  if (process.env.FORCE_CREATE_USER === interaction.user.id) {
    logger.info(interaction.user, 'Force-Creating User in DB...');
    lookup = getUserEntry(interaction.user, true);
    await (await lookup)?.save();
  }
  if (item.requiredBotPermissions.length > 0) {
    if (!lookup) lookup = getUserEntry(interaction.user);
    const dbUser = await lookup;
    if (!dbUser) {
      await interaction.reply({
        embeds: [
          new Embed()
            .error("You don't have permission to interact with this button.")
            .setFooter({
              text: 'ERR_NO_DB_ENTRY',
            }),
        ],
      });
      return;
    }
    const permissions = await getUserPermissionsFromEntry(dbUser);
    const missingPermissions = item.requiredBotPermissions.filter(
      v => !permissions[v],
    );
    if (missingPermissions.length !== 0) {
      await interaction.reply({
        embeds: [
          new Embed()
            .error(
              `You don't have permission to interact with this button.
Missing Permission${
                missingPermissions.length === 1
                  ? ` \`${missingPermissions[0]}\``
                  : `s:
${missingPermissions.map(v => `- \`${v}\``).join('\n')}`
              }`,
            )
            .setFooter({
              text: 'ERR_MISSING_PERMS',
            }),
        ],
        ephemeral: true,
      });
      return;
    }
  }
  item.invoke(interaction);
};

bot.on(Events.InteractionCreate, async interaction => {
  logger.debug(`Interaction Created by ${interaction.user?.id}`);
  if (interaction.isChatInputCommand())
    return await handleChatInputCommand(interaction);
  if (interaction.isButton()) return await handleButtonInteraction(interaction);
});
